package d2;


import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TimeZone;

import com.dingtalk.api.DefaultDingTalkClient;
import com.dingtalk.api.DingTalkClient;
import com.dingtalk.api.request.OapiDepartmentListRequest;
import com.dingtalk.api.request.OapiGettokenRequest;
import com.dingtalk.api.request.OapiUserListbypageRequest;
import com.dingtalk.api.response.OapiDepartmentListResponse;
import com.dingtalk.api.response.OapiGettokenResponse;
import com.dingtalk.api.response.OapiUserListbypageResponse;
import com.dingtalk.api.response.OapiDepartmentListResponse.Department;
import com.dingtalk.api.response.OapiUserListbypageResponse.Userlist;
import com.taobao.api.ApiException;

import cn.cybozu.api.CybozuFile;
import cn.cybozu.api.KintoneRecord;
import cn.cybozu.api.KintoneRest;

public abstract class D2Connector
{

	private static final SimpleDateFormat DATE_FORMATTER = new SimpleDateFormat("yyyy-MM-dd");
	private static final SimpleDateFormat DATETIME_FORMATTER = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
	private static final SimpleDateFormat DATETIME_PARSER = new SimpleDateFormat("yyyy-MM-dd HH:mm");
	
	private static final long TOKEN_VALID_INTERVAL = 7200 * 1000L; // access tokenの有効期間7200s
	private static File tmpDir    = null;
	
	private String appKey = null;
	private String appSecret = null;
	
	private KintoneRest rest = new KintoneRest();
	private long appId = 0;
	private long spaceId = 0;
	private String apiToken = null;
	
	private String accessToken = null;
	private long validTime = 0L;
	

	
	static
	{
		DATE_FORMATTER.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
		DATETIME_FORMATTER.setTimeZone(TimeZone.getTimeZone("UTC"));
		DATETIME_PARSER.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));

		tmpDir = new File(System.getProperty("java.io.tmpdir") + "qyd2");
		try
		{
			tmpDir.mkdir();
		}
		catch(Exception e)
		{
			throw e;
		}
	}
	
	public D2Connector(String appKey, String appSecret, String domain, long appId, long spaceId, String apiToken)
	{
		rest.setDomain(domain);
		this.appKey = appKey;		
		this.appSecret = appSecret;
		this.appId = appId;
		this.spaceId = spaceId;
		this.apiToken = apiToken;
	}
	/**
	 * yyyy-mm-dd形式の文字列をDate型に変換
	 * @param value
	 * @return
	 * @throws ParseException
	 */
	public static Date parseDate(String value)
		throws ParseException
	{
		if(value == null || value.length() == 0)
		{
			return null;
		}
		return DATE_FORMATTER.parse(value);
	}
	public static Date parseDateTime(String value)
			throws ParseException
	{
		if(value == null || value.length() == 0)
		{
			return null;
		}
		return DATETIME_PARSER.parse(value);
	}
	/**
	 * Date型からyyyy-mm-dd文字列に変換
	 * @param value
	 * @return
	 */
	public static String formatDate(Date value)
	{
		if(value == null)
		{
			return null;
		}
		return DATE_FORMATTER.format(value);
	}
	/**
	 * Date型からUTC(yyyy-mm-ddThh:mi:ssZ)文字列に変換
	 * @param value
	 * @return
	 */
	public static String formatDateTime(Date value)
	{
		if(value == null)
		{
			return null;
		}
		return DATETIME_FORMATTER.format(value);
	}
	/**
	 * AccessTokenの取得
	 * @return
	 * @throws Exception
	 */
	public String getAccessToken()
		throws ApiException
	{
		long currentTime = System.currentTimeMillis();
		
		if(currentTime < validTime)
		{
			return accessToken;
		}
		DefaultDingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/gettoken");
		OapiGettokenRequest request = new OapiGettokenRequest();
		request.setAppkey(appKey);
		request.setAppsecret(appSecret);
		request.setHttpMethod("GET");
		OapiGettokenResponse response = client.execute(request);	
		accessToken = response.getAccessToken();
		validTime = currentTime + TOKEN_VALID_INTERVAL;
		return accessToken;
	}
	public String getDomain()
	{
		return rest.getDomain();
	}
	protected void setAppId(long appId)
	{
		this.appId = appId;
	}
	protected void setSpaceId(long spaceId)
	{
		this.spaceId = spaceId;
	}
	protected void setApiToken(String apiToken)
	{
		this.apiToken = apiToken;
	}
	protected List<KintoneRecord> getRecordsFromKintone(String query, String[] fields)
		throws Exception
	{
		return rest.getAllRecords(appId, spaceId, apiToken, query, fields);
	}
	protected void postRecordsToKintone(List<KintoneRecord> recs)
		throws Exception
	{
		rest.postRecords(appId, spaceId, apiToken, recs);
	}
	protected void putRecordsToKintone(List<KintoneRecord> recs)
			throws Exception
	{
		rest.putRecords(appId, spaceId, apiToken, recs);
	}
	protected void postRecordToKintone(KintoneRecord rec)
			throws Exception
	{
		rest.postRecord(appId, spaceId, apiToken, rec);
	}
	protected void putRecordToKintone(KintoneRecord rec)
			throws Exception
	{
		rest.putRecord(appId, spaceId, apiToken, rec);
	}	
	protected String uploadFileToKintone(File file)
		throws Exception
	{
		return rest.uploadFile(spaceId, apiToken, file);
	}
	protected void deleteRecordsToKintone(List<KintoneRecord> delRecs)
		throws Exception
	{
		rest.deleteAllRecords(appId, spaceId, apiToken, delRecs);
	}
	/**
	 * 全ユーザ情報の取得
	 * @return
	 * @throws Exception
	 */
	protected Map<String, Userlist> getAllUsers() throws Exception
	{
		final long SIZE = 100L;
		
		Map<String, Userlist> userMap = new HashMap<String, Userlist>();
		
		for(Long id : getAllDepartments().keySet())
		{
			long offset = 0L;
			
			DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/user/listbypage");
			OapiUserListbypageRequest request = new OapiUserListbypageRequest();
			request.setHttpMethod("GET");
			request.setSize(SIZE);
			request.setOrder("entry_desc");
				
			for(;;)
			{
				request.setDepartmentId(id);
				request.setOffset(offset);
					
				OapiUserListbypageResponse execute = client.execute(request, getAccessToken());
				
				List<Userlist> users = execute.getUserlist();
				if(users.size() == 0)
				{
					break;
				}
				for(Userlist user : users)
				{
					userMap.put(user.getUserid(), user);
				}
				offset += SIZE;
			}
		}
		return userMap;
	}
	/**
	 * 全組織情報の取得
	 * @return
	 * @throws Exception
	 */
	public Map<Long, Department> getAllDepartments() throws Exception
	{
		DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/department/list");
		
		OapiDepartmentListRequest request = new OapiDepartmentListRequest();
		request.setId("1");
		request.setFetchChild(true);
		request.setHttpMethod("GET");
		
		OapiDepartmentListResponse response = client.execute(request, getAccessToken());
		
		Map<Long, Department> depMap = new HashMap<Long, Department>();
		
		Department root = new Department();
		root.setId(1L);
		root.setName("ROOT");
		depMap.put(root.getId(), root);
		
		for(Department d : response.getDepartment())
		{
			depMap.put(d.getId(), d);
		}
		return depMap;
	}

	/**
	 * 画像ファイルcopy
	 * @param url
	 * @return
	 * @throws Exception
	 */
	protected CybozuFile copyImage(String url)
		throws Exception
	{
		String[] names = url.split("/");
		
		URLConnection conn = (new URL(url)).openConnection();
		InputStream in = conn.getInputStream();

		File file = new File(tmpDir, names[names.length-1]);  //保存先
		file.delete();
		FileOutputStream out = new FileOutputStream(file, false);
		byte[] bytes = new byte[512];
		while(true){
		    int ret = in.read(bytes);
		    if(ret == -1) break;
		    out.write(bytes, 0, ret);
		}
		out.close();
		in.close();
		
		CybozuFile cf = new CybozuFile();
		cf.setFileKey(uploadFileToKintone(file));
		file.delete();
		return cf;
	}
}
